home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #if (EDENKERNEL || TRANSFER)
- #include "EdenKernel/h/stdTypes.h"
- #include "EdenKernel/h/kEvents.h"
- #endif (EDENKERNEL || TRANSFER)
-
- /* An implementation of malloc(3), free(3) using the QuickFit method.
- * Guy Almes, May 1983.
- *
- * Cf. MALLOC(3) in the Unix manual for external specifications.
- *
- * Cf. Chuck Weinstock's PhD thesis for a discussion of the techniques
- * used. (Charles Weinstock, Dynamic Storage Allocation Techniques,
- * April 1976, CMU)
- * nb: Unlike the original QuickFit, this implementation assumes that
- * TailFit always works. Also, we want to allow for some other user to
- * be using sbrk.
- *
- * NOTE: change made on 11/29/84 by Mike Schwartz to call HoldSigs and
- * ReleaseSigs at beginning and end of malloc if signals weren't
- * already held (and running in Eden Kernel or EFT context). This is needed
- * in case a Unix routine that uses malloc is called, so that signals
- * will be held as needed to protect the critical region variables during
- * the allocation.
- *
- * Hacked by oystr. While the external specification was met, the
- * internal behaviour of the standard malloc(3) was not. To wit:
- * areas free'd do not have their contents touched until reallocated
- * (Almes actually fixed this after considerable pleading); it is
- * possible to do multiple free's of the same area - that is "x = malloc();
- * free(x); free(x);" causes no damage. This turkey originally did
- * not detect such a situation even though the multiple free's caused
- * it to trash the list structures and blow up at some future malloc
- * call. Realloc was also a disaster area, making the assumption that
- * the old block was in use, which is not necessarily the case.
- */
- /* The parts of Unix used by this module:
- */
-
- /* From BRK(2):
- */
- extern char *brk(); /* set break to addr */
- extern char *sbrk(); /* add incr to break */
-
- /* From END(3):
- */
- extern char end; /* first byte beyond bss region */
-
- /* Design parameters; these can be changed to tune the implementation
- * to a specific application.
- */
-
- #define GrainSize 8
- #define LogGrainSize 3
- #define HeaderSize sizeof(int)
- /* number of bytes: every allocated block is
- * (k+1) * GrainSize, for k >= MinGrains
- * GrainSize == (1 << LogGrainSize)
- */
-
- #define MinBytes 0
- #define MaxBytes (SBrkChunk - HeaderSize) /* = 1020 bytes */
- #define MinGrains 0
- #define MaxGrains ((MaxBytes-MinBytes+1) >> LogGrainSize)
- /* The implementation is tuned to use ExactFit for blocks in the range
- * MinBytes .. MaxBytes
- */
-
- #define BtoG(b) ( ((b)-(GrainSize-HeaderSize) + GrainSize-1) >> LogGrainSize )
- /* convert a number of bytes to a number of grains */
- #define GtoB(g) ( ((g) << LogGrainSize) + (GrainSize-HeaderSize) )
- /* and vice versa */
-
- #define Nil ((char *) 0)
- /* a nil pointer; often coerced to various flavors of pointers */
-
- #define SBrkChunk 1024
- /* the number of bytes to get from sbrk when growing the Tail */
- #define roundUp(a,b) ((char *) ( ((int)(a) + (b)-1) & ~((b)-1) ))
- /* round up an address to the nearest 1k boundary like sbrk does */
-
- /* header for Big blocks allocated via MiscFit */
- typedef struct bigHeader {
- struct bigHeader *bNext; /* the next field links available blocks */
- unsigned bSize; /* the size of the block in bytes */
- } bHeader, *bHeaderPtr;
-
- /* header for Small blocks allocated via ExactFit */
- typedef union smallHeader {
- unsigned sSize; /* the size of a used block in bytes */
- union smallHeader *sNext; /* the next field links available blocks */
- } sHeader, *sHeaderPtr;
-
- static char *TailMin = &end; /* points to 1st byte of Tail */
- static char *TailMax = &end; /* points just beyond end of Tail */
- /* invariants: TailMin and TailMax are each on int boundaries.
- * The area with addresses TailMin <= addr < TailMax is available.
- * &end <= TailMin <= TailMax == sbrk(0).
- */
-
- /*
- * Free/in use magic numbers. WARNING: if we ever get into 16MB+
- * virtual addresses ( >24 bits), you will have to change the headers.
- * The upper byte of the size field contains INUSEMAGIC if the
- * block has been malloc'd but not freed, 0 if the block is free.
- */
- #define INUSEMAGIC 0x55
- #define SETMAGIC 0x55000000
- #define CLRMAGIC 0x00FFFFFF
-
- static char *TailFit(nBytes)
- register unsigned nBytes;
- {
- register char *oldTailMin;
- #ifdef GORP
- fprintf(stderr,
- " TailFit(%d) called. Tail: %x - %x.\n", nBytes, TailMin, TailMax);
- #endif
- while (TailMax < TailMin+nBytes) {
- register char *oldBreak = sbrk(SBrkChunk);
- if ((int) oldBreak == -1) {
- fprintf(stderr, "sbrk returned a -1!!");
- return ( Nil );
- }
- if (oldBreak != TailMax) { /* someone else did an sbrk! */
- #ifdef GORP
- fprintf(stderr,
- "TailFit: pushed TailMin from %x to %x.\n",
- TailMin, roundUp(oldBreak, sizeof(int)));
- #endif
- TailMin = roundUp(oldBreak, sizeof(int));
- }
- TailMax = oldBreak + SBrkChunk;
- if (TailMax != roundUp(TailMax, SBrkChunk)) {
- /* bring TailMax to a page */
- #ifdef GORP
- fprintf(stderr,
- "TailFit: rounding TailMax from %x to %x.\n",
- TailMax, roundUp(TailMax, SBrkChunk));
- #endif
- TailMax = roundUp(TailMax, SBrkChunk);
- (void) brk(TailMax);
- }
- } /* we now know we have enough in the Tail */
- oldTailMin = TailMin;
- TailMin += nBytes;
- #ifdef GORP
- fprintf(stderr,
- " TailFit returns %x. Tail: %x - %x.\n", oldTailMin, TailMin, TailMax);
- #endif
- return ( oldTailMin );
- } /* TailFit */
-
- static bHeaderPtr BigList;
- /* BigLists points to a ring of zero or more available blocks, each marked
- * with both a size and a next field. This ring is used in the MiscFit
- * portion of the algorithm, which is a simple FirstFit for very large blocks.
- */
-
- static char *MiscFit(nBytes)
- register unsigned nBytes;
- {
- register bHeaderPtr CurrentHdr, PreviousHdr;
- register unsigned oldSize;
- register char *newBlock = Nil;
- #ifdef GORP
- fprintf(stderr, " MiscFit(%d) called.\n", nBytes);
- #endif
- if (BigList != (bHeaderPtr) Nil) {
- PreviousHdr = BigList;
- CurrentHdr = PreviousHdr->bNext;
- oldSize = PreviousHdr->bSize; /* save real size field, then ... */
- PreviousHdr->bSize = nBytes; /* ... forge a stopper value */
- while (CurrentHdr->bSize < nBytes) {
- PreviousHdr = CurrentHdr;
- CurrentHdr = PreviousHdr->bNext;
- } /* this loop always terminates due to the stopper value */
- BigList->bSize = oldSize; /* restore old size */
- if (CurrentHdr->bSize >= nBytes) { /* MiscFit worked */
- PreviousHdr->bNext = CurrentHdr->bNext;
- BigList =
- (PreviousHdr==CurrentHdr ? (bHeaderPtr) Nil : PreviousHdr);
- CurrentHdr->bSize |= SETMAGIC;
- newBlock = (char *) (CurrentHdr+1);
- }
- }
- #ifdef GORP
- fprintf(stderr, " MiscFit returns %x.\n", newBlock);
- #endif
- return( newBlock );
- } /* MiscFit */
-
- /* p = malloc(nBytes);
- * where nBytes is unsigned number of bytes needed and p is some pointer
- */
-
- static sHeaderPtr AvailList[MaxGrains-MinGrains+1];
- /* AvailList[MinGrains .. MaxGrains] is for ExactFit blocks
- *
- * AvailList[MinGrains..MaxGrains] each point to a LIFO singly-linked list of
- * equal sized blocks. These lists are used in the ExactFit portion of the
- * algorithm.
- */
-
- char *malloc(reqBytes)
- unsigned reqBytes;
- {
- register char *newBlock;
- register unsigned nGrains = BtoG(reqBytes);
- #if (EDENKERNEL || TRANSFER)
- extern int SigsHeld;
- int SigsWereHeld;
-
- SigsWereHeld = SigsHeld;
- if (!SigsWereHeld) HoldSigs(); /* Make sure HoldSigs is called once (if
- it wasn't already) if running in Eden
- Kernel context */
- #endif (EDENKERNEL || TRANSFER)
-
- #ifdef GORP
- fprintf(stderr, "malloc(%d) called.\n", reqBytes);
- #endif
-
- if (reqBytes > MaxBytes) {
- register unsigned nBytes = GtoB(nGrains);
- newBlock = MiscFit(nBytes);
- if (newBlock == Nil) {
- bHeaderPtr newRawBlock =
- (bHeaderPtr) TailFit(nBytes + sizeof(bHeader));
- if (newRawBlock == (bHeaderPtr) Nil) {
- newBlock = Nil;
- } else {
- newBlock = (char *) (newRawBlock+1);
- newRawBlock->bSize = nBytes | SETMAGIC;
- }
- }
- } else {
- register sHeaderPtr newRawBlock = AvailList[nGrains];
- if (newRawBlock != (sHeaderPtr) Nil) {
- AvailList[nGrains] = newRawBlock->sNext;
- newRawBlock->sSize = GtoB(nGrains) | SETMAGIC;
- newBlock = (char *) (newRawBlock + 1);
- } else {
- newRawBlock = (sHeaderPtr) TailFit(GtoB(nGrains)+sizeof(sHeader));
- if (newRawBlock == (sHeaderPtr) Nil) {
- newBlock = Nil;
- } else {
- newBlock = (char *) (newRawBlock + 1);
- newRawBlock->sSize = GtoB(nGrains) | SETMAGIC;
- }
- }
- }
- #ifdef GORP
- fprintf(stderr, "malloc returns %x.\n", newBlock);
- fflush(stderr);
- #endif
-
- #if (EDENKERNEL || TRANSFER)
- if (!SigsWereHeld) ReleaseSigs();
- #endif (EDENKERNEL || TRANSFER)
-
- return( newBlock );
- } /* malloc */
-
- free(ptr)
- char *ptr;
- {
- register sHeaderPtr oldBlock = ((sHeaderPtr) ptr) - 1;
- register unsigned nGrains = BtoG( (oldBlock->sSize & CLRMAGIC) );
-
- #if (EDENKERNEL || TRANSFER)
- extern int SigsHeld;
- int SigsWereHeld;
-
- SigsWereHeld = SigsHeld;
- if (!SigsWereHeld) HoldSigs(); /* Make sure HoldSigs is called once (if
- it wasn't already) if running in Eden
- Kernel context */
- #endif (EDENKERNEL || TRANSFER)
- if ( ! (oldBlock->sSize & SETMAGIC) ) {
- /* already free */
- #ifdef GORP
- fprintf(stderr, "free(%x) called returning %d grains (already free!).\n",
- ptr, nGrains);
- #endif
- return;
- }
- else oldBlock->sSize &= CLRMAGIC;
-
- #ifdef GORP
- fprintf(stderr, "free(%x) called returning %d grains.\n", ptr, nGrains);
- #endif
-
- if (nGrains <= MaxGrains) {
- oldBlock->sNext = AvailList[nGrains];
- AvailList[nGrains] = oldBlock;
- } else {
- register bHeaderPtr oldBlock = ((bHeaderPtr) ptr) - 1;
- if (BigList == (bHeaderPtr) Nil) {
- BigList = oldBlock;
- oldBlock->bNext = oldBlock;
- } else {
- oldBlock->bNext = BigList->bNext;
- BigList->bNext = oldBlock;
- }
- }
-
- #ifdef GORP
- fflush(stderr);
- #endif
- #if (EDENKERNEL || TRANSFER)
- if (!SigsWereHeld) ReleaseSigs();
- #endif (EDENKERNEL || TRANSFER)
-
- } /* free */
-
- char *realloc(oldBlock, nBytes)
- register char *oldBlock;
- unsigned nBytes;
- {
- register char *newBlock = malloc(nBytes);
-
- #if (EDENKERNEL || TRANSFER)
- extern int SigsHeld;
- int SigsWereHeld;
-
- SigsWereHeld = SigsHeld;
- if (!SigsWereHeld) HoldSigs(); /* Make sure HoldSigs is called once (if
- it wasn't already) if running in Eden
- Kernel context */
- #endif (EDENKERNEL || TRANSFER)
-
- if (newBlock != Nil) {
- register int *newPtr = (int *) newBlock;
- register int *oldPtr = (int *) oldBlock;
- register sHeaderPtr oldRawBlock = ((sHeaderPtr) oldPtr) - 1;
- register unsigned nGrains = ((oldRawBlock->sSize > nBytes)
- ? BtoG(nBytes)
- : BtoG((oldRawBlock->sSize & CLRMAGIC)));
- while (nGrains > 0) {
- *newPtr++ = *oldPtr++;
- *newPtr++ = *oldPtr++;
- nGrains--;
- }
- *newPtr++ = *oldPtr++;
- free(oldBlock);
- }
-
- #if (EDENKERNEL || TRANSFER)
- if (!SigsWereHeld) ReleaseSigs();
- #endif (EDENKERNEL || TRANSFER)
- return( newBlock );
- } /* realloc */
-